1.2.2 更详细的向量
向量用于通过单一名称组合相关信号,以便更方便地进行操作。例如,声明 wire [7:0] w; 定义了一个名为 w 的8位向量,这等效于拥有8个独立的导线。
向量声明
向量必须按照以下格式声明:
type [upper:lower] vector_name;
类型 [高位:低位] 向量名;
其中,类型 指定了向量的数据类型,通常是 wire 或 reg。如果你正在声明输入或输出端口,类型还可以包括端口类型(如 input 或 output)。一些例子包括:
- wire [7:0] w; // 8位 wire
- reg [4:1] x; // 4位 reg
- output reg [0:0] y; // 1位 reg 也是输出端口
- input wire [3:-2] z; // 允许负范 围的6位 wire 输入
- output [3:0] a; // 默认为 wire 类型的4位输出线,除非另外指定
- wire [0:7] b; // 8位 wire,其中 b[0] 是最高有效位
向量的字节序(或非正式地称为“方向”)指的是最低有效位是否具有较低的索引(小端序,例如 [3:0])还是较高的索引(大端序,例如 [0:3])。在Verilog中,一旦向量以特定的字节序声明,就必须始终以相同的方式使用它。不一致可能导致奇怪的错误。
隐式网络
隐式网络往往是难以检测的错误来源。在Verilog中,通过赋值语句或未声明就连接到模块端口可以隐式创建net类型的信号。隐式网络总是单比特的 wire,如果你本意是要使用向量,这就会引发错误。可以通过指令禁用隐式网络的创建:default_nettype none
- wire [2:0] a, c; // 定义了两个三位的向量
- assign a = 3'b101; // 将a赋值为三位二进制数101
- assign b = a; // b隐式地创建为一个wire类型,并从a得到同样的值101,此处有省略的wire声明,实际应为wire b;
- assign c = b; // 由于b被隐式地当作一位宽处理,所以c被错误地赋值为001,此处预期可能是想保留b的全部三位值
- my_module i1 (d,e); // d和e的位宽默认为一位,如果不另外声明的话。 // 如果端口本意是要定义为向量,这将可能成为一个错误。
添加`default_nettype none指令后,第二行代码会报错,这样一来上述的错误会更加明显,因为Verilog会要求明确指定所有的net类型,避免了隐式的wire声明可能导致的问题。
非打包数组与打包数组
在声明中,你可能已经注意到向量的索引写在向量名称之前,这声明了数组的“打包”维度,即位被一起“打包”成一个整体(这在仿真器中是有意义的,但在硬件中则不是)。非打包 维度则在名称之后声明,通常用于声明内存数组。由于ECE253课程未涵盖内存数组,我们在此课程中未使用过非打包数组。
详情请参阅 https://www.asic-world.com/systemverilog/data_types10.html
- reg [7:0] mem [255:0]; //这行代码定义了一个存储器数组,它包含了256个未打包(unpacked)元素,每一个元素都是一个8位打包(packed)的寄存器向量(reg)
- reg mem2 [28:0]; //这行代码定义了另一个数组,它有29个未打包元素,每个元素是一个单比特(1-bit)的寄存器(reg)。
访问向量元素:部分选择(Part-Select)
访问整个向量直接使用向量名称即可。例如,assign w = a;
将整个4位向量 a 分配给8位向量 w。如果左右两边的长度不匹配,则会自动填充零或截断。
部分选择操作符可用于访问向量的一部分,例如:
- w[3:0] // 只取 w 的低4位
- x[1] // x 的最低位
- x[1:1] // 同样是 x 的最低位
- z[-1:-2] // z 的最低两位(注意此处示例非法,正确应为 z[1:0])
- b[3:0] // 非法,向量部分选择必须与声明时的方向一致
- b[0:3] // b 的高4位
- assign w[3:0] = b[0:3];// - 将 b 的高 4 位赋值给 w 的低 4 位。即 w[3]=b[0], w[2]=b[1], 以此类推。
实践练习
构建一个组合逻辑电路,将一个半字(16位,[15:0])分割为低字节 [7:0] 和高字节 [15:8]。
模块声明
`default_nettype none // 禁止隐式网络,减少某些类型的错误
module top_module(
input wire [15:0] in, // 16位输入
output wire [7:0] out_hi, // 高8位输出
output wire [7:0] out_lo // 低8位输出6);